<template>
  <n-space justify="center">
    <n-button @click="showLevel" :focusable="false"> 难度：{{ level }} </n-button>
    <n-button @click="setgrid" :focusable="false">再来一局</n-button>
  </n-space>
  <div @contextmenu.prevent style="width: 100%; margin-top: 10px">
    <div v-for="(row, rowi) in grid" class="grid" :key="row">
      <div
        v-for="(col, coli) in row"
        :key="col"
        @click="onclick(rowi, coli)"
        @contextmenu.prevent="changestate(rowi, coli)"
        @dblclick="clickaround(rowi, coli)"
        :class="{ state0: col.state != 3, state3: col.state == 3 }"
      >
        <div v-if="col.state == 3 && col.arroundnum != 0">{{ col.arroundnum }}</div>
        <div v-if="col.ismine == 1 && this.showMine">💣</div>
        <div>{{ col.state == 1 ? '🚩' : col.state == 2 ? '?' : '' }}</div>
      </div>
    </div>
  </div>
  <n-space justify="center" :size="50">
    <div>⏱：{{ second }}</div>
    <div>🚩:{{ flagnum }}</div>
  </n-space>

  <n-modal v-model:show="show">
    <DifficultyModel @difficulty="changeDifficulty" />
  </n-modal>
  <HistoryRecord :record="record"></HistoryRecord>
</template>

<script>
import { ref } from 'vue'
import DifficultyModel from './components/DifficultyModel.vue'
import HistoryRecord from './components/HistoryRecord.vue'
import { record } from '@/utils/useRecord'
import JSConfetti from 'js-confetti'
import { message } from './utils/discreteApi'

export default {
  components: {
    DifficultyModel,
    HistoryRecord
  },
  setup() {
    const confetti = new JSConfetti()
    let timer
    let isfirst = true
    let show = ref(false)
    let grid = ref([])
    let second = ref(0)
    let flagnum = ref(0)
    let showMine = ref(false)
    let end = ref(false)

    const createGrid = (rownum, colnum) => {
      return Array.from({ length: rownum }, () =>
        Array.from({ length: colnum }, () => ({
          ismine: 0,
          state: 0 //0默认 1红旗 2问号 3翻开
        }))
      )
    }
    function setgrid() {
      confetti.clearCanvas()
      grid.value = createGrid(rownum.value, colnum.value)
      isfirst = true
      showMine.value = false
      end.value = false
      clearInterval(timer)
      second.value = 0
      flagnum.value = minenum.value
    }

    let level = ref()
    let rownum = ref()
    let colnum = ref()
    let minenum = ref()
    let showLevel = () => {
      show.value = true
      confetti.clearCanvas()
    }
    function changeDifficulty(data) {
      if (!data) {
        data = {
          rownum: 9,
          colnum: 9,
          minenum: 10,
          level: '初级'
        }
      }
      rownum.value = data.rownum
      colnum.value = data.colnum
      minenum.value = data.minenum
      level.value = data.level
      show.value = false
      setgrid()
    }
    let levelStorage = localStorage.getItem('level')
    changeDifficulty(JSON.parse(levelStorage))

    function getaround(rowi, coli) {
      let mineNum = 0
      let rowmin = rowi == 0 ? 0 : rowi - 1
      let rowmax = rowi == rownum.value - 1 ? rownum.value - 1 : rowi + 1
      let colmin = coli == 0 ? 0 : coli - 1
      let colmax = coli == colnum.value - 1 ? colnum.value - 1 : coli + 1

      for (var i = rowmin; i <= rowmax; i++) {
        for (var j = colmin; j <= colmax; j++) {
          if (grid.value[i][j].ismine == 1) {
            mineNum++
          }
        }
      }
      return mineNum
    }
    function setmine(rowi, coli) {
      let coordinates = []
      while (coordinates.length < minenum.value) {
        let coordinate = {
          rowi: Math.floor(Math.random() * rownum.value),
          coli: Math.floor(Math.random() * colnum.value)
        }
        let notaround =
          coordinate.rowi < rowi - 1 ||
          coordinate.rowi > rowi + 1 ||
          coordinate.coli > coli + 1 ||
          coordinate.coli < coli - 1
        let nothave = JSON.stringify(coordinates).indexOf(JSON.stringify(coordinate)) == -1
        if (notaround && nothave) {
          coordinates = coordinates.concat(coordinate)
          grid.value[coordinate.rowi][coordinate.coli].ismine = 1
        }
      }
      for (var i = 0; i < rownum.value; i++) {
        for (var j = 0; j < colnum.value; j++) {
          grid.value[i][j].arroundnum = getaround(i, j)
        }
      }
    }
    let gameStart = (rowi, coli) => {
      if (!isfirst) return
      setmine(rowi, coli)
      timer = setInterval(() => {
        second.value++
        if (record.value[level.value] === second.value) {
          message.info('超越过去的自己固然重要，但慢下来才能享受游戏的乐趣')
        }
      }, 1000)
      isfirst = false
    }

    function gameEnd(isWin) {
      end.value = true
      clearInterval(timer)
      if (isWin) {
        gameWin()
        return
      }
      showMine.value = true
      message.error('boom')
      confetti.addConfetti({
        emojis: ['💣', '💥']
      })
    }
    function gameWin() {
      let isNewRecord =
        (second.value < record.value[level.value] || !record.value[level.value]) &&
        level.value !== '自定义'

      if (isNewRecord) {
        record.value[level.value] = second.value
      }

      message.success('恭喜你，' + (isNewRecord ? '新纪录' : '你赢了'))
      confetti.addConfetti()
    }

    return {
      rownum,
      colnum,
      minenum,
      show,
      grid,
      second,
      flagnum,
      showMine,
      end,
      setgrid,
      level,
      gameStart,
      gameEnd,
      record,
      showLevel,
      changeDifficulty
    }
  },
  methods: {
    onclick(rowi, coli) {
      if (this.end || this.grid[rowi][coli].state == 1) {
        return
      }
      this.gameStart(rowi, coli)
      if (this.grid[rowi][coli].ismine == 1) {
        this.gameEnd()
        return
      }
      this.grid[rowi][coli].state = 3
      if (this.getopennum() == this.colnum * this.rownum - this.minenum) {
        this.gameEnd(true)
        return
      }
      if (this.grid[rowi][coli].arroundnum == 0) {
        this.autoclick0(rowi, coli)
      }
    },
    autoclick0(rowi, coli) {
      let rowmin = rowi == 0 ? 0 : rowi - 1
      let rowmax = rowi == this.rownum - 1 ? this.rownum - 1 : rowi + 1
      let colmin = coli == 0 ? 0 : coli - 1
      let colmax = coli == this.colnum - 1 ? this.colnum - 1 : coli + 1

      for (var i = rowmin; i <= rowmax; i++) {
        for (var j = colmin; j <= colmax; j++) {
          if (this.grid[i][j].state == 0 || this.grid[i][j].state == 2) {
            this.onclick(i, j)
          }
        }
      }
    },
    changestate(rowi, coli) {
      if (this.end) {
        return
      }
      let state = this.grid[rowi][coli].state
      if (state == 0) {
        this.flagnum--
        this.grid[rowi][coli].state = 1
      } else if (state == 1) {
        this.flagnum++
        this.grid[rowi][coli].state = 2
      } else if (state == 2) {
        this.grid[rowi][coli].state = 0
      }
    },
    clickaround(rowi, coli) {
      let flagnum = 0
      let rowmin = rowi == 0 ? 0 : rowi - 1
      let rowmax = rowi == this.rownum - 1 ? this.rownum - 1 : rowi + 1
      let colmin = coli == 0 ? 0 : coli - 1
      let colmax = coli == this.colnum - 1 ? this.colnum - 1 : coli + 1

      for (var i = rowmin; i <= rowmax; i++) {
        for (var j = colmin; j <= colmax; j++) {
          if (this.grid[i][j].state == 1) {
            flagnum++
          }
        }
      }
      if (flagnum == this.grid[rowi][coli].arroundnum) {
        for (let i = rowmin; i <= rowmax; i++) {
          for (let j = colmin; j <= colmax; j++) {
            if (this.grid[i][j].state == 0 || this.grid[i][j].state == 2) {
              this.onclick(i, j)
            }
          }
        }
      }
    },
    getopennum() {
      let opennum = 0
      for (var i = 0; i < this.rownum; i++) {
        for (var j = 0; j < this.colnum; j++) {
          if (this.grid[i][j].state == 3) {
            opennum++
          }
        }
      }
      return opennum
    }
  }
}
</script>

<style>
#app {
  margin-top: 60px;
  user-select: none;
}

.grid {
  display: flex;
  justify-content: center;
}

.grid div {
  width: 2rem;
  height: 2rem;
  line-height: 2rem;
  text-align: center;
  margin: 1px;
}

.state0 {
  background-color: #42b983;
  position: relative;
}
.state0 div {
  position: absolute;
}
.state3 {
  background-color: beige;
}
</style>
